from fastapi import APIRouter,Depends,HTTPException
from fastapi import Request, status
from sqlalchemy import select, func,update
from sqlalchemy.orm import selectinload
from models.seckill import Seckill
from datetime import datetime
from schemas.response import ResultSchema, SeckillSchema, SeckillPageSchema,OrderSchema
from hooks.dependencies import get_db_session
from models import AsyncSession
from utils.auth import AuthHandler
from schemas.request import BuySchema
from models.order import Order
from alipay import AliPay
from alipay.utils import AliPayConfig
import settings
from alipay import AliPay
from alipay.utils import AliPayConfig


router = APIRouter(prefix="/seckill", tags=["seckill"])
auth_handler = AuthHandler()


with open('keys/app_private.key', mode='r') as f:
    app_private_key_string = f.read()
with open('keys/alipay_public.pem', mode='r') as f:
    alipay_public_key_string = f.read()

alipay = AliPay(
    appid=settings.ALIPAY_APP_ID,
    # app_notify_url="http://www.example.com/notify",  # 默认回调 url
    app_notify_url=settings.ALIPAY_NOTIFY_URL,
    app_private_key_string=app_private_key_string,
    # 支付宝的公钥，验证支付宝回传消息使用，不是你自己的公钥,
    alipay_public_key_string=alipay_public_key_string,
    sign_type="RSA2",  # RSA 或者 RSA2
    # 沙箱环境需要设置debug=True
    debug=True,  # 默认 False
    verbose=True,  # 输出调试数据
    config=AliPayConfig(timeout=15)  # 可选，请求超时时间
)


@router.get('/ing', response_model=ResultSchema, summary="获取进行中的秒杀")
async def get_ing_seckills(session:AsyncSession=Depends(get_db_session), page: int = 1, size: int = 10):
    now = datetime.now()
    # 查询总数
    async with session.begin():
        count_stmt = select(func.count(Seckill.id)).where(
            Seckill.start_time < now, 
            Seckill.end_time >= now
        )
        count_result = await session.execute(count_stmt)
        total = count_result.scalar() or 0
        
        # 查询分页数据
        stmt = select(Seckill).options(selectinload(Seckill.commodity)).where(
            Seckill.start_time < now, 
            Seckill.end_time >= now
        ).order_by(Seckill.create_time.desc()).offset((page-1)*size).limit(size)
        result = await session.execute(stmt)
        seckills = result.scalars().all()
        
        # 使用Pydantic自动转换
        seckill_list = [SeckillSchema.model_validate(seckill) for seckill in seckills]
        
        page_data = SeckillPageSchema(
            list=seckill_list,
            total=total,
            page=page,
            size=size
        )
        
        return ResultSchema(
            code=status.HTTP_200_OK,
            message="正在查询成功",
            data=page_data
        )

@router.get('/will', response_model=ResultSchema, summary="获取即将的秒杀")
async def get_will_seckills(session:AsyncSession=Depends(get_db_session), page: int = 1, size: int = 10):
    now = datetime.now()
    async with session.begin():    
        # 查询总数
        count_stmt = select(func.count(Seckill.id)).where(
            Seckill.start_time > now
        )
        count_result = await session.execute(count_stmt)
        total = count_result.scalar() or 0
        
        # 查询分页数据
        stmt = select(Seckill).options(selectinload(Seckill.commodity)).where(
            Seckill.start_time > now
        ).order_by(Seckill.create_time.desc()).offset((page-1)*size).limit(size)
        result = await session.execute(stmt)
        seckills = result.scalars().all()
        
        # 使用Pydantic自动转换
        seckill_list = [SeckillSchema.model_validate(seckill) for seckill in seckills]
        
        page_data = SeckillPageSchema(
            list=seckill_list,
            total=total,
            page=page,
            size=size
        )
        return ResultSchema(
            code=status.HTTP_200_OK,
            message="即将秒杀查询成功",
            data=page_data
        )

@router.get('/detail/{id}', response_model=ResultSchema, summary="获取秒杀详情")
async def get_seckill_detail(id: int,session:AsyncSession=Depends(get_db_session)):    
    async with session.begin():
        stmt = select(Seckill).options(selectinload(Seckill.commodity)).where(
            Seckill.id == id
        )
        result = await session.execute(stmt)
        seckill = result.scalar()
        
        if not seckill:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="秒杀不存在"
            )
        return ResultSchema(
            code=status.HTTP_200_OK,
            message="秒杀详情查询成功",
            data=SeckillSchema.model_validate(seckill)
        )
    
@router.post('/buy', summary="秒杀")
async def buy(params: BuySchema, session: AsyncSession = Depends(get_db_session), user_id: int = Depends(auth_handler.auth_access_dependency)):
    seckill_id = params.seckill_id
    count = params.count
    address = params.address
    
    async with session.begin():
        # 检查用户是否已经参与过该秒杀活动
        order_result = await session.execute(select(Order).where(Order.user_id == user_id, Order.seckill_id == seckill_id))
        if order_result.scalar():
            raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail='您已参与过此秒杀活动')
        
        # 使用行锁查询秒杀信息，同时预加载商品信息
        seckill_result = await session.execute(select(Seckill).options(selectinload(Seckill.commodity)).where(Seckill.id == seckill_id).with_for_update())
        seckill = seckill_result.scalars().first()
        if not seckill:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='秒杀活动不存在')
        
        # 检查库存
        stock_value = getattr(seckill, 'stock', 0)
        if stock_value <= 0:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='秒杀活动已结束')
        if stock_value < count:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='库存不足')
        if getattr(seckill, 'sk_per_max_count', 0) < count:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='超出最大秒杀数量')
        
        # 更新库存
        await session.execute(update(Seckill).where(Seckill.id == seckill.id).values(stock=stock_value - count))
    async with session.begin():
        # 创建订单
        sk_price = getattr(seckill, 'sk_price', 0)
        total_amount = sk_price * count
        order = Order(user_id=user_id, seckill_id=seckill_id, count=count, amount=total_amount, address=address)
        session.add(order)
        await session.flush()
        
        order_string=alipay.api_alipay_trade_app_pay(
            out_trade_no=str(order.id),
            total_amount=str(total_amount),
            subject=seckill.commodity.title,
        )
        
        return {"alipay_order":order_string}
